import random, pygame, sys, time
from pygame.locals import *

FPS = 15
WINDOWWIDTH = 1281
WINDOWHEIGHT = 721
FLOORNUM = 5
ROOMNUM = 7
assert WINDOWWIDTH % ROOMNUM == 0, "Window width must be a multiple of cell size."
assert WINDOWHEIGHT % ROOMNUM == 0, "Window height must be a multiple of cell size."
CELLWIDTH = int(WINDOWWIDTH / ROOMNUM)
CELLHEIGHT = int(WINDOWHEIGHT / ROOMNUM)

#             R    G    B
WHITE     = (255, 255, 255)
BLACK     = (  0,   0,   0)
RED       = (255,   0,   0)
GREEN     = (  0, 255,   0)
DARKGREEN = (  0, 155,   0)
DARKGRAY  = ( 40,  40,  40)
BGCOLOR = BLACK

def enum(**enums):
    return type('Enum', (), enums)

TroopType = enum(SOLDIER = "soldier", SNIPER = "sniper", MEDIC = "medic", SCOUT = "scout", MELEE = "melee", HEAVY = "heavy")

RewardType = enum(NONE = 0, money = 1, XP = 2, SCIENCE = 3, ARMOUR = 4, WEAPON = 5)

RoomType = enum(EMPTY = "empty", SHAFT = "shaft", MONEY = "money", SCIENCE = "science", MED_BAYS = "med_bays", POWER = "power")


class Troop:
    def __init__(self, name_, troopType_, level_):
        self.name = name_
        self.level = level_
        self.injured = False
        self.xp = 0
        self.troopType = troopType_

        # sets stats based on troopType
        if self.troopType == TroopType.SOLDIER:
            self.health = (100 * self.level) + random.randint(-5,5)
            self.maxHealth = self.health
            self.armour = 1
            self.damage = (10 + self.level) + random.randint(-2,2)
            self.evasion = (5) + random.randint(-1,1)
            self.accuracy = (90) + random.randint(-15,0)
        elif self.troopType == TroopType.SNIPER:
            self.health = (80 * self.level) + random.randint(-5,5)
            self.maxHealth = self.health
            self.armour = 0
            self.damage = (20 + self.level) + random.randint(-2,2)
            self.evasion = (50) + random.randint(-5,5)
            self.accuracy = (50) + random.randint(-5,5)
        elif self.troopType == TroopType.MEDIC:
            self.health = (100 * self.level) + random.randint(-5,5)
            self.maxHealth = self.health
            self.armour = 1
            self.damage = (5 + self.level) + random.randint(-1,1)
            self.evasion = (5) + random.randint(-1,1)
            self.accuracy = (90) + random.randint(-15,0)
        elif self.troopType == TroopType.SCOUT:
            self.health = (100 * self.level) + random.randint(-5,5)
            self.maxHealth = self.health
            self.armour = 1
            self.damage = (8 + self.level) + random.randint(-1,1)
            self.evasion = (25) + random.randint(-4,4)
            self.accuracy = 90 + random.randint(-10,0)
        elif self.troopType == TroopType.MELEE:
            self.health = (110 * self.level) + random.randint(-5,5)
            self.maxHealth = self.health
            self.armour = 1
            self.damage = (15 + self.level) + random.randint(-2,2)
            self.evasion = (0) + random.randint(0,2)
            self.accuracy = 100 + random.randint(-5,-1)
        elif self.troopType == TroopType.HEAVY:
            self.health = (120 * self.level) + random.randint(-5,5)
            self.maxHealth = self.health
            self.armour = 3
            self.damage = (8 + self.level) + random.randint(-2,2)
            self.evasion = (0) + random.randint(0,2)
            self.accuracy = (100) + random.randint(-10,-1)

class Mission:
    def __init__(self):
        self.name = "Steve"
        self.desc = "This is a mission"
        self.health = random.randint(90, 110)
        self.armour = random.randint(0, 2)
        self.damage = random.randint(9, 11)
        self.money = random.randint(50, 150)
        self.xp = random.randint(50, 150)
        self.difficulty = 1 # remove this once difficulty_choice is complete

    def attempt(self, troopList):
        livingTroops = len(troopList)
        while livingTroops > 0 and self.health > 0: # while there are troops left and mission not complete
            for i in range (0, len(troopList)):
                if troopList[i].injured == False: # if troop is injured miss combat
                    if random.randint(0, 100) >= troopList[i].evasion:# evasion chance
                        troopList[i].health -= (self.damage - troopList[i].armour)
                    
                    if troopList[i].troopType == TroopType.MEDIC: # heals other troops every turn
                        for j in range (len(troopList)):
                            troopList[j].health += troopList[i].damage
                            if troopList[j].health > 0: # revives injured troop
                                troopList[j].injured = false
                                livingTroops += 1
                    else:
                        if random.randint(0, 100) <= troopList[i].accuracy: # hit chance
                            self.health -= (troopList[i].damage - self.armour)
                    if troopList[i].health <= 0: # injures troop when health is empty
                        troopList[i].injured = True
                        livingTroops -= 1
        return troopList
        
    

    def difficulty(self):
        # handles choice of difficulty and modifies mission attributes based on choice      
        for event in pygame.event.get(): # event handling loop
            if event.type == QUIT:
                terminate()
            elif event.type == KEYDOWN:
                # user inputs a choice for difficulty here  
                if (event.key == K_1):
                    self.difficulty = 0.8
                if (event.key == K_2):
                    self.difficulty = 1
                if (event.key == K_3):
                    self.difficulty = 1.2
                if (event.key == K_4):
                    self.difficulty = 2
        # end for loop

        # modifies mission attributes depending on difficulty_choice
        self.health *= self.difficulty
        self.armour += self.difficulty
        self.damage *= self.difficulty
        self.money *= self.difficulty
        self.xp *= self.difficulty

class Room():
    width = CELLWIDTH
    height = CELLHEIGHT

    def __init__(self, X_, Y_, ):
        positionX = X_
        positionY = Y_

        if positionX == 3:
            type = RoomType.SHAFT
        else:
            type = RoomType.EMPTY

class Base():
    Cave = []
    for i in range(0, FLOORNUM):
        x = []
        for j in range(0, ROOMNUM):
            x.append(Room(j,i))
        Cave.append(x)

class Game: 
    def __init__(self):
        # name, troopType, level
        self.troop1 = Troop("troop1", "soldier", 1) 
        self.troop2 = Troop("troop2", "sniper", 1) 
        self.troop3 = Troop("troop3", "heavy", 1) 
        self.troop4 = Troop("troop4", "scout", 1) 

        # list of troops
        self.troopList = [self.troop1, self.troop2, self.troop3, self.troop4]
        self.troopList = list(self.troopList)

        # list of missions - unused at the moment
        self.missionList = [None]
        self.missionList = list(self.missionList)

        self.money = 1000
        self.science = 100
        self.power = 100

        #make base
        self.base = Base()
        
    def generateReward(self):
        reward = random.randint(RewardType.NONE, RewardType.WEAPON)
        #if reward == RewardType.NONE:
            #no reward 
        if reward == RewardType.money:
            self.money += self.mission1.money * 2
        elif reward == RewardType.XP:
            self.mission1.xp += self.mission1.xp * 2
        elif reward == RewardType.SCIENCE:
            self.science += random.randint(50, 150) * self.mission1.difficulty
        #elif reward == RewardType.ARMOUR:
            #give armour
        #elif reward == RewardType.WEAPON:
            #give weapon

    def game_update(self):
        for event in pygame.event.get(): # event handling loop
            if event.type == QUIT:
                terminate()
            elif event.type == KEYDOWN:
                            if (event.key == K_q):
                                sfx_win.play(1)
                            elif (event.key == K_w):
                                sfx_dig.play(1)
                            elif (event.key == K_e):
                                sfx_build.play(1)
                            elif (event.key == K_r):
                                sfx_dayOver.play(1)    
                            elif (event.key == K_SPACE):
                                    self.mission1 = Mission()
                                    self.troopList = self.mission1.attempt(self.troopList)
                                    if self.mission1.health <= 0:
                                            #gain reward
                                            self.generateReward()
                                            #for i in range(len(self.troopList)):
                                                    #if self.troopList[i].injured == True:
                                                            #if random.randint(0, 100) < 75: #minus number of med_bays * 5
                                                                    #self.troopList.pop(i)
                                            for i in range (len(self.troopList)):
                                                    self.troopList[i].xp += self.mission1.xp
                                                    if self.troopList[i].xp >= (((self.troopList[i].level) * (self.troopList[i].level)) * 10) + 100:
                                                            self.troopList[i].level += 1
                                                            self.troopList[i].xp -= (((self.troopList[i].level) * (self.troopList[i].level)) * 10) + 100
                                
    def game_render(self):
        #render stuff
        DISPLAYSURF.fill(BGCOLOR)
        render_info(self)
        render_troops(self)
        for x in range(0, WINDOWWIDTH, CELLWIDTH): # draw vertical lines
            pygame.draw.line(DISPLAYSURF, WHITE, (x, 0), (x, WINDOWHEIGHT))
            for y in range(206, WINDOWHEIGHT, CELLHEIGHT): # draw horizontal lines
                pygame.draw.line(DISPLAYSURF, WHITE, (0, y), (WINDOWWIDTH, y))

        pygame.display.update()
        FPSCLOCK.tick(FPS)  
        
def render_info(game):
    moneySurf = BASICFONT.render('Money: %s' % (game.money), True, WHITE)
    moneyRect = moneySurf.get_rect()
    moneyRect.topleft = (10, 10)
    DISPLAYSURF.blit(moneySurf, moneyRect)

    scienceSurf = BASICFONT.render('Science: %s' % (game.science), True, WHITE)
    scienceRect = scienceSurf.get_rect()
    scienceRect.topleft = (10, 30)
    DISPLAYSURF.blit(scienceSurf, scienceRect)

    powerSurf = BASICFONT.render('Power: %s' % (game.power), True, WHITE)
    powerRect = powerSurf.get_rect()
    powerRect = powerSurf.get_rect()
    powerRect.topleft = (10, 50)
    DISPLAYSURF.blit(powerSurf, powerRect)

    troopSurf = BASICFONT.render('Troops: %s' % (len(game.troopList)), True, WHITE)
    troopRect = troopSurf.get_rect()
    troopRect.topleft = (10, 70)
    DISPLAYSURF.blit(troopSurf, troopRect)

def render_troops(game):
    keySurf = BASICFONT.render(("Name        Type       Level      XP       Health    Armour    Damage    Accuracy    Evasion    XP    Injured"), True, WHITE)
    keyRect = keySurf.get_rect()
    keyRect.topleft = (350, 10)
    DISPLAYSURF.blit(keySurf, keyRect)

    for x in range(0, len(game.troopList)):
            a = '%s' %game.troopList[x].name
            b = '%s' % game.troopList[x].troopType
            c = '%s' % game.troopList[x].level
            d = '%s' % game.troopList[x].health
            e = '/%s' % game.troopList[x].maxHealth
            f = '%s' % game.troopList[x].armour
            g = '%s' % game.troopList[x].damage
            h = '%s' % game.troopList[x].accuracy
            i = '%s' % game.troopList[x].evasion
            j = '%s' % game.troopList[x].xp
            k = '%s' % game.troopList[x].injured

            tnameSurf = BASICFONT.render((a), True, WHITE)
            tnameRect = tnameSurf.get_rect()
            tnameRect.topleft = (350, (((x+1)*15)+25))
            DISPLAYSURF.blit(tnameSurf, tnameRect)

            ttypeSurf = BASICFONT.render((b), True, WHITE)
            ttypeRect = ttypeSurf.get_rect()
            ttypeRect.topleft = (435, (((x+1)*15)+25))
            DISPLAYSURF.blit(ttypeSurf, ttypeRect)

            tlevelSurf = BASICFONT.render((c), True, WHITE)
            tlevelRect = tlevelSurf.get_rect()
            tlevelRect.topright = (555, (((x+1)*15)+25))
            DISPLAYSURF.blit(tlevelSurf, tlevelRect)

            txpSurf = BASICFONT.render((j), True, WHITE)
            txpRect = txpSurf.get_rect()
            txpRect.topright = (630, (((x+1)*15)+25))
            DISPLAYSURF.blit(txpSurf, txpRect)

            thealthSurf = BASICFONT.render((d+e), True, WHITE)
            thealthRect = thealthSurf.get_rect()
            thealthRect.topleft = (665, (((x+1)*15)+25))
            DISPLAYSURF.blit(thealthSurf, thealthRect)
def main():
    init()
    while True:
        runGame()

def init():
    global FPSCLOCK, DISPLAYSURF, BASICFONT, sfx_win, sfx_dig, sfx_build, sfx_dayOver

    pygame.init()
    FPSCLOCK = pygame.time.Clock()
    DISPLAYSURF = pygame.display.set_mode((WINDOWWIDTH, WINDOWHEIGHT))
    BASICFONT = pygame.font.Font('freesansbold.ttf', 18)
    pygame.display.set_caption('BaseCom')
    
    pygame.mixer.music.load('data/audio/music/ftc.wav') #loads audio loop
    pygame.mixer.music.set_volume(0.1)
    pygame.mixer.music.play(-1, 0.0) #plays audio on a loop
    
    sfx_win = pygame.mixer.Sound('data/audio/sfx/win.mp3')  #load sound
    sfx_win.set_volume(1)
    sfx_dig = pygame.mixer.Sound('data/audio/sfx/digging.mp3')  #load sound
    sfx_dig.set_volume(1)
    sfx_build = pygame.mixer.Sound('data/audio/sfx/building.mp3')  #load sound
    sfx_build.set_volume(1)
    sfx_dayOver = pygame.mixer.Sound('data/audio/sfx/dayOver.wav')  #load sound
    sfx_dayOver.set_volume(1)

def runGame():
    game = Game()
    while True: # main game loop
        game_over = game.game_update()
        game.game_render()
        if game_over == True:
            return # game over, stop running the game

def terminate():
    pygame.mixer.music.stop()
    pygame.quit()
    sys.exit()

if __name__ == "__main__":
    main()
